home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / syslxmod.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-12-22  |  7.5 KB  |  285 lines

  1. #ident "$Id: syslxmod.c,v 1.11 2004/12/22 07:17:31 hpa Exp $"
  2. /* ----------------------------------------------------------------------- *
  3.  *   
  4.  *   Copyright 1998-2004 H. Peter Anvin - All Rights Reserved
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
  9.  *   Boston MA 02111-1307, USA; either version 2 of the License, or
  10.  *   (at your option) any later version; incorporated herein by reference.
  11.  *
  12.  * ----------------------------------------------------------------------- */
  13.  
  14. /*
  15.  * syslxmod.c - Code to provide a SYSLINUX code set to an installer.
  16.  */
  17.  
  18. #define _XOPEN_SOURCE 500    /* Required on glibc 2.x */
  19. #define _BSD_SOURCE
  20. #include <stdio.h>
  21. #include <inttypes.h>
  22. #include <string.h>
  23. #include <stddef.h>
  24.  
  25. #include "syslinux.h"
  26.  
  27. #define LDLINUX_MAGIC    0x3eb202fe
  28.  
  29. enum bs_offsets {
  30.   bsJump            = 0x00,
  31.   bsOemName         = 0x03,
  32.   bsBytesPerSec     = 0x0b,
  33.   bsSecPerClust     = 0x0d,
  34.   bsResSectors      = 0x0e,
  35.   bsFATs            = 0x10,
  36.   bsRootDirEnts     = 0x11,
  37.   bsSectors         = 0x13,
  38.   bsMedia           = 0x15,
  39.   bsFATsecs         = 0x16,
  40.   bsSecPerTrack     = 0x18,
  41.   bsHeads           = 0x1a,
  42.   bsHiddenSecs      = 0x1c,
  43.   bsHugeSectors     = 0x20,
  44.  
  45.   /* FAT12/16 only */
  46.   bs16DriveNumber   = 0x24,
  47.   bs16Reserved1     = 0x25,
  48.   bs16BootSignature = 0x26,
  49.   bs16VolumeID      = 0x27,
  50.   bs16VolumeLabel   = 0x2b,
  51.   bs16FileSysType   = 0x36,
  52.   bs16Code          = 0x3e,
  53.  
  54.   /* FAT32 only */
  55.   bs32FATSz32       = 36,
  56.   bs32ExtFlags      = 40,
  57.   bs32FSVer         = 42,
  58.   bs32RootClus      = 44,
  59.   bs32FSInfo        = 48,
  60.   bs32BkBootSec     = 50,
  61.   bs32Reserved      = 52,
  62.   bs32DriveNumber   = 64,
  63.   bs32Reserved1     = 65,
  64.   bs32BootSignature = 66,
  65.   bs32VolumeID      = 67,
  66.   bs32VolumeLabel   = 71,
  67.   bs32FileSysType   = 82,
  68.   bs32Code          = 90,
  69.   
  70.   bsSignature     = 0x1fe
  71. };
  72.  
  73. #define bsHead      bsJump
  74. #define bsHeadLen   (bsOemName-bsHead)
  75. #define bsCode        bs32Code    /* The common safe choice */
  76. #define bsCodeLen   (bsSignature-bs32Code)
  77.  
  78. /*
  79.  * Access functions for littleendian numbers, possibly misaligned.
  80.  */
  81. static inline uint8_t get_8(const unsigned char *p)
  82. {
  83.   return *(const uint8_t *)p;
  84. }
  85.  
  86. static inline uint16_t get_16(const unsigned char *p)
  87. {
  88. #if defined(__i386__) || defined(__x86_64__)
  89.   /* Littleendian and unaligned-capable */
  90.   return *(const uint16_t *)p;
  91. #else
  92.   return (uint16_t)p[0] + ((uint16_t)p[1] << 8);
  93. #endif
  94. }
  95.  
  96. static inline uint32_t get_32(const unsigned char *p)
  97. {
  98. #if defined(__i386__) || defined(__x86_64__)
  99.   /* Littleendian and unaligned-capable */
  100.   return *(const uint32_t *)p;
  101. #else
  102.   return (uint32_t)p[0] + ((uint32_t)p[1] << 8) +
  103.     ((uint32_t)p[2] << 16) + ((uint32_t)p[3] << 24);
  104. #endif
  105. }
  106.  
  107. static inline void set_16(unsigned char *p, uint16_t v)
  108. {
  109. #if defined(__i386__) || defined(__x86_64__)
  110.   /* Littleendian and unaligned-capable */
  111.   *(uint16_t *)p = v;
  112. #else
  113.   p[0] = (v & 0xff);
  114.   p[1] = ((v >> 8) & 0xff);
  115. #endif
  116. }
  117.  
  118. static inline void set_32(unsigned char *p, uint32_t v)
  119. {
  120. #if defined(__i386__) || defined(__x86_64__)
  121.   /* Littleendian and unaligned-capable */
  122.   *(uint32_t *)p = v;
  123. #else
  124.   p[0] = (v & 0xff);
  125.   p[1] = ((v >> 8) & 0xff);
  126.   p[2] = ((v >> 16) & 0xff);
  127.   p[3] = ((v >> 24) & 0xff);
  128. #endif
  129. }
  130.  
  131. /* Patch the code so that we're running in stupid mode */
  132. void syslinux_make_stupid(void)
  133. {
  134.   /* Access only one sector at a time */
  135.   set_16(syslinux_bootsect+0x1FC, 1);
  136. }
  137.   
  138. void syslinux_make_bootsect(void *bs)
  139. {
  140.   unsigned char *bootsect = bs;
  141.  
  142.   memcpy(bootsect+bsHead, syslinux_bootsect+bsHead, bsHeadLen);
  143.   memcpy(bootsect+bsCode, syslinux_bootsect+bsCode, bsCodeLen);
  144. }
  145.  
  146. /*
  147.  * Check to see that what we got was indeed an MS-DOS boot sector/superblock;
  148.  * Return NULL if OK and otherwise an error message;
  149.  */
  150. const char *syslinux_check_bootsect(const void *bs)
  151. {
  152.   int veryold;
  153.   int sectorsize;
  154.   long long sectors, fatsectors, dsectors;
  155.   long long clusters;
  156.   int rootdirents, clustersize;
  157.   const unsigned char *sectbuf = bs;
  158.  
  159.   veryold = 0;
  160.  
  161.   /* Must be 0xF0 or 0xF8..0xFF */
  162.   if ( get_8(sectbuf+bsMedia) != 0xF0 &&
  163.        get_8(sectbuf+bsMedia) < 0xF8 )
  164.     goto invalid;
  165.   
  166.   sectorsize = get_16(sectbuf+bsBytesPerSec);
  167.   if ( sectorsize == 512 )
  168.     ; /* ok */
  169.   else if ( sectorsize == 1024 || sectorsize == 2048 || sectorsize == 4096 )
  170.     return "only 512-byte sectors are supported";
  171.   else
  172.     goto invalid;
  173.  
  174.   clustersize = get_8(sectbuf+bsSecPerClust);
  175.   if ( clustersize == 0 || (clustersize & (clustersize-1)) )
  176.     goto invalid;        /* Must be nonzero and a power of 2 */
  177.  
  178.   sectors = get_16(sectbuf+bsSectors);
  179.   sectors = sectors ? sectors : get_32(sectbuf+bsHugeSectors);
  180.  
  181.   dsectors = sectors - get_16(sectbuf+bsResSectors);
  182.  
  183.   fatsectors = get_16(sectbuf+bsFATsecs);
  184.   fatsectors = fatsectors ? fatsectors : get_32(sectbuf+bs32FATSz32);
  185.   fatsectors *= get_8(sectbuf+bsFATs);
  186.   dsectors -= fatsectors;
  187.  
  188.   rootdirents = get_16(sectbuf+bsRootDirEnts);
  189.   dsectors -= (rootdirents+sectorsize/32-1)/sectorsize;
  190.  
  191.   if ( dsectors < 0 || fatsectors == 0 )
  192.     goto invalid;
  193.  
  194.   clusters = dsectors/clustersize;
  195.  
  196.   if ( clusters < 0xFFF5 ) {
  197.     /* FAT12 or FAT16 */
  198.  
  199.     if ( !get_16(sectbuf+bsFATsecs) )
  200.       goto invalid;
  201.  
  202.     if ( get_8(sectbuf+bs16BootSignature) == 0x29 ) {
  203.       if ( !memcmp(sectbuf+bs16FileSysType, "FAT12   ", 8) ) {
  204.     if ( clusters >= 0xFF5 )
  205.       return "more than 4084 clusters but claims FAT12";
  206.       } else if ( !memcmp(sectbuf+bs16FileSysType, "FAT16   ", 8) ) {
  207.     if ( clusters < 0xFF5 )
  208.       return "less than 4084 clusters but claims FAT16";
  209.       } else if ( memcmp(sectbuf+bs16FileSysType, "FAT     ", 8) ) {
  210.     static char fserr[] = "filesystem type \"????????\" not supported";
  211.     memcpy(fserr+17, sectbuf+bs16FileSysType, 8);
  212.     return fserr;
  213.       }
  214.     }
  215.   } else if ( clusters < 0x0FFFFFF5 ) {
  216.     /* FAT32 */
  217.     /* Moving the FileSysType and BootSignature was a lovely stroke of M$ idiocy */
  218.     if ( get_8(sectbuf+bs32BootSignature) != 0x29 ||
  219.      memcmp(sectbuf+bs32FileSysType, "FAT32   ", 8) )
  220.       goto invalid;
  221.   } else {
  222.     goto invalid;
  223.   }
  224.   
  225.   return NULL;
  226.  
  227.  invalid:
  228.   return "this doesn't look like a valid FAT filesystem";
  229. }
  230.  
  231. /*
  232.  * This patches the boot sector and the first sector of ldlinux.sys
  233.  * based on an ldlinux.sys sector map passed in.  Typically this is
  234.  * handled by writing ldlinux.sys, mapping it, and then overwrite it
  235.  * with the patched version.  If this isn't safe to do because of
  236.  * an OS which does block reallocation, then overwrite it with
  237.  * direct access since the location is known.
  238.  *
  239.  * Return 0 if successful, otherwise -1.
  240.  */
  241. int syslinux_patch(const uint32_t *sectors, int nsectors)
  242. {
  243.   unsigned char *patcharea, *p;
  244.   int nsect = (syslinux_ldlinux_len+511) >> 9;
  245.   uint32_t csum;
  246.   int i, dw;
  247.  
  248.   if ( nsectors < nsect )
  249.     return -1;
  250.  
  251.   /* First sector need pointer in boot sector */
  252.   set_32(syslinux_bootsect+0x1F8, *sectors++);
  253.   nsect--;
  254.   
  255.   /* Search for LDLINUX_MAGIC to find the patch area */
  256.   for ( p = syslinux_ldlinux ; get_32(p) != LDLINUX_MAGIC ; p += 4 );
  257.   patcharea = p+8;
  258.  
  259.   /* Set up the totals */
  260.   dw = syslinux_ldlinux_len >> 2; /* COMPLETE dwords! */
  261.   set_16(patcharea, dw);
  262.   set_16(patcharea+2, nsect);    /* Does not include the first sector! */
  263.  
  264.   /* Set the sector pointers */
  265.   p = patcharea+8;
  266.  
  267.   memset(p, 0, 64*4);
  268.   while ( nsect-- ) {
  269.     set_32(p, *sectors++);
  270.     p += 4;
  271.   }
  272.  
  273.   /* Now produce a checksum */
  274.   set_32(patcharea+4, 0);
  275.  
  276.   csum = LDLINUX_MAGIC;
  277.   for ( i = 0, p = syslinux_ldlinux ; i < dw ; i++, p += 4 )
  278.     csum -= get_32(p);        /* Negative checksum */
  279.  
  280.   set_32(patcharea+4, csum);
  281.  
  282.     return 0;
  283. }
  284.  
  285.